package com.woniuxy.service.impl;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.woniuxy.api.RemoteProductServer;
import com.woniuxy.dao.OrderDao;
import com.woniuxy.entity.Order;
import com.woniuxy.entity.Product;
import com.woniuxy.entity.utils.ResponseEntity;
import com.woniuxy.service.OrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.beanutils.BeanUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.transaction.Transactional;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 马宇航
 * @Do: order订单服务层，基于Feign来调用product服务
 * @DateTime: 22/06/21/0021 下午 3:17
 * @Component: 成都蜗牛学苑
 **/

@Service
public class OrderServiceImplFeign implements OrderService {
    @Autowired
    OrderDao orderDao;
    @Autowired
    RemoteProductServer remoteProductServer;
    @Autowired
    RedissonClient redissonClient;

    @Override
//    @HystrixCommand
    @GlobalTransactional
    public ResponseEntity createOne(Integer pid, Integer count) {

        //1.添加分布式锁：使用方式类似 Lock lock = new ReentrantLock();
        RLock lock = redissonClient.getLock("lock:order");
        ResponseEntity response  = remoteProductServer.findOneById(pid);
        //这个名字就是key
        try {
            //第一个参数是 等待获取锁的最长时间，第二个参数 持有锁的最长时间
            lock.tryLock(10,10, TimeUnit.SECONDS);
            //        occasionalTimeoutMethod();//偶尔抽风的方法
            //先去商品服务中，获取目标商品

            if (response == null) return ResponseEntity.ERROR;
            //获取响应码，判断是否是200请求.由于是一个Object需要转成Integer
            Integer code = Integer.parseInt(response.get(ResponseEntity.ResponseStatus.CODE.value())+"");
            //这个就是响应码的 200
            int success = HttpStatus.OK.value();
            //如果响应码不是200，说明，没有商品id。
            if (code != success){
                return ResponseEntity.ERROR;
            }
            //获取商品信息，只能使用map接收,底层使用的是LinkedHashMap！
            Map map = (Map) response.get(ResponseEntity.ResponseStatus.DATA.value());
            Product product = new Product();
            try {
                //map快速映射实体类进行赋值
                BeanUtils.populate(product,map);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            //订单入库
            Order order = new Order();
            order.setUid(1);
            order.setUsername("周杰伦");
            order.setPid(product.getPid());
            order.setPrice(product.getPrice());
            order.setNumber(count);
            order.setPname(product.getName());
            //扣减商品
            Integer stock = product.getStock();
            Integer newStock = stock-count;
            //商品不能超卖
            if (newStock < 0){
                return ResponseEntity.ERROR;
            }
            //新建，因为没有传主键oid
            orderDao.save(order);
            //更新商品剩余数量
            product.setStock(newStock);
            //通过请求，访问商品服务的，新增(更新)商品库存
            response= remoteProductServer.addProduct(product);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放锁，都一定要在这个里面进行
            lock.unlock();
        }
        return response;
    }

    @Override
//    @HystrixCommand(
//            fallbackMethod = "deleteMarketFallback",//如果发生熔断后，就直接进入降级方法
//            commandProperties = {
//                    @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//开启断路器
//                    @HystrixProperty(
//                            name = "circuitBreaker.requestVolumeThreshold",
//                            value = "10"),//设置10S范围内，可以接收10个请求
//                    @HystrixProperty(
//                            name = "circuitBreaker.sleepWindowInMilliseconds",
//                            value = "3000")
//                    ,//熔断器的休眠时间为3S，3S范围内：熔断器都是出于半开状态
//                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
//                            value = "2000"),//设置超时时间
//                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50")
//                    //设置超过50%的比例异常，就开启熔断
//            }
//    )
    public ResponseEntity searchProduct(Integer minimumInventory, Integer maxInventory) {
//        occasionalTimeoutMethod();
        //方案一 平铺模式
//        return remoteProductServer.search1(minimumInventory,maxInventory);
        //方案二 map模式
        Map map = new HashMap();
        map.put("minimumInventory",minimumInventory);
        map.put("maxInventory",maxInventory);
        return remoteProductServer.search2(map);
    }
    /**
     * 在order服务中，开发一个间歇性偶尔抽风的方法。
     * ChangeLog : 1. 创建 (22/06/24/0024 下午 2:26 [马宇航]);
     *
     * @return void
    */
    public void occasionalTimeoutMethod(){
        Random random = new Random();
        int i = random.nextInt(3 - 1 + 1) + 1;
        if (i != 3 ){
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 熔断方法 deleteMarketFallback
     * @return
     */
    public ResponseEntity deleteMarketFallback(Integer minimumInventory, Integer maxInventory){
        System.out.println("进入熔断方法了！！！" +
                "");
        ResponseEntity error = ResponseEntity.ERROR;
        error.put("error","删除市场服务，已达熔断阈值！"+minimumInventory+"/"+maxInventory+"/");
        return error;
    }

}
